/*
 * AIEngine a new generation network intrusion detection system.
 *
 * Copyright (C) 2013-2023  Luis Campo Giralte
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
 * Boston, MA  02110-1301, USA.
 *
 * Written by Luis Campo Giralte <luis.camp0.2009@gmail.com>
 *
 */
#ifndef SRC_FLOW_FLOWTABLE_H_
#define SRC_FLOW_FLOWTABLE_H_

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <fstream>
#include <limits>
#include "Flow.h"
#include "Protocol.h"
#include "FlowCache.h"
#include "Cache.h"
#include "OutputManager.h"
#include "json.hpp"

namespace aiengine {

class FlowManager;

struct FlowNode {
	SharedPointer<Flow> flow = nullptr;
	FlowNode *next = nullptr;
	FlowNode *prev = nullptr;

	void reset() { next = prev = nullptr; flow.reset(); }
};

class FlowIterator {
public :

       	FlowIterator (FlowNode* temp) : itr(temp) {}
       	FlowIterator (const FlowIterator& myitr) : itr(myitr.itr) {}

       	FlowIterator& operator++ () {

               	itr = itr->next;
               	return *this;
       	}

       	FlowIterator operator++ (int) {

       		auto tmp(*this);
               	itr = itr->next;
		return tmp;
	}

        // iterator traits
        using difference_type = SharedPointer<Flow>;
        using value_type = SharedPointer<Flow>;
        using pointer = SharedPointer<Flow>*;
        using reference = SharedPointer<Flow>&;
        using iterator_category = std::forward_iterator_tag;

	bool operator== (const FlowIterator& rhs) { return itr == rhs.itr; }
	bool operator!= (const FlowIterator& rhs) { return itr != rhs.itr; }
	const SharedPointer<Flow>& operator*() const { return itr->flow; }
	SharedPointer<Flow>& operator*() { return itr->flow; }
	const SharedPointer<Flow>* operator->() const { return &itr->flow; }
private:
	FlowNode* itr;
};

class FlowTable  {
public:
	friend class FlowManager;

	explicit FlowTable() {
		cache_->setDynamicAllocatedMemory(true);
	}

	void detach(FlowNode *node);
	void attach(FlowNode *node);

	std::size_t size() const { return table_.size(); }

	FlowIterator begin() const { return FlowIterator(head); }
	FlowIterator end() const { return FlowIterator(nullptr); }
protected:
	FlowNode *head = nullptr;
	FlowNode *tail = nullptr;
	Cache<FlowNode>::CachePtr cache_ = Cache<FlowNode>::CachePtr(new Cache<FlowNode>());
        std::unordered_map<unsigned long, SharedPointer<FlowNode>> table_;
};

} // namespace aiengine

#endif  // SRC_FLOW_FLOWTABLE_H_
